package parserjc.jaccie;

/**
 * @author Ralf Meyer,
 * "Erstellung von Compiler Compiler Komponenten f�r die Zielsprache Java"
 * UniBwM - ID26/96
 *
 * The following methods are implemented by Christoph Reich:
 * rule(int, String[])
 */
import java.util.*;
import java.io.*;

public abstract class SICParser extends SICModule {
    protected Vector sicActionTable = new Vector();
    protected Vector sicRules = new Vector();
    protected SICParserInput sicPin = null;
    protected SICTree sicTree = null;
    protected SICStack sicStack = null;

    public final static int SHIFT = 0;
    public final static int REDUCE = 1;
    public final static int ACCEPT = 2;
    public final static int ERROR = 3;

    protected final void actionTable( int line, String symbol, int action , int index ) {
        while (sicActionTable.size()<=line) sicActionTable.addElement(new Hashtable());
        Integer[] ActionAndIndex = new Integer[2];
          ActionAndIndex[0] = new Integer(action);
          ActionAndIndex[1] = new Integer(index);
        ((Hashtable)sicActionTable.elementAt(line)).put(symbol,ActionAndIndex);
    }

    protected final void actionTable( int line, String symbol, int action ) {
        while (sicActionTable.size()<=line) sicActionTable.addElement(new Hashtable());
        Integer[] ActionAndIndex = new Integer[2];
          ActionAndIndex[0] = new Integer(action);
          ActionAndIndex[1] = new Integer(-1);
        ((Hashtable)sicActionTable.elementAt(line)).put(symbol,ActionAndIndex);
    }

    protected final void rule( int ruleNumber, String rule ) {
        StringTokenizer strTkzr = new StringTokenizer(rule," ",false);
        String[] help = new String[strTkzr.countTokens()];
        for (int i=0; i<help.length; i++)
            help[i] = (String)strTkzr.nextElement();
        while (sicRules.size()<=ruleNumber) sicRules.addElement(null);
        sicRules.setElementAt(help,ruleNumber);
    }

    /**
     * Fills the Parser with a rule.
     */
    protected final void rule(int ruleNumber, String[] rule) {
        while (sicRules.size()<=ruleNumber) sicRules.addElement(null);
        sicRules.setElementAt(rule,ruleNumber);
    }


    // Public Instance Methods

    public final int getAction( int line, String symbol ) {
        if (sicActionTable.size()<=line) return ERROR;
          else {
            Integer[] ActionAndIndex = (Integer[])((Hashtable)sicActionTable.elementAt(line)).get(symbol);
            if (ActionAndIndex==null) return ERROR;
              else return ActionAndIndex[0].intValue();
          }
    }

    public final int getIndex( int line, String symbol ) {
        if (sicActionTable.size()<=line) return -1;
          else {
            Integer[] ActionAndIndex = (Integer[])((Hashtable)sicActionTable.elementAt(line)).get(symbol);
            if (ActionAndIndex==null) return -1;
              else return ActionAndIndex[1].intValue();
          }
    }

    public final String[] getRule( int ruleNumber ) {
        if (sicRules.size()<=ruleNumber) return null;
          else return (String[])sicRules.elementAt(ruleNumber);
    }

    public final String[][] getRules() {
        String[][] answer = new String[sicRules.size()][];
        for (int i=0; i<sicRules.size(); i++) answer[i] = getRule(i);
        return answer;
    }

    public final String getRuleAsString( int ruleNumber ) {
        String answer = null;
        String[] rule = getRule(ruleNumber);
        if (rule!=null) {
            answer = rule[0] + " ::=";
            for (int i=1; i<rule.length; i++) answer = answer + " " + rule[i];
        }
        return answer;
    }

    public final String getRulesAsString() {
        String cr = System.getProperties().getProperty("line.separator");
        StringBuffer answer = new StringBuffer();
        String rule;
        for (int i=0; i<sicRules.size(); i++) {
           rule = getRuleAsString(i);
           if (rule!=null) {
               for (int t=0; t<Integer.toString(sicRules.size()).length()-Integer.toString(i).length(); t++)
                   answer.append(' ');
               answer.append(i);
               answer.append(": " + rule + cr);
           }
        }
        return answer.toString();
    }

    public final String[] nonTerminals() {
        String[][] rules = getRules();
        Vector help = new Vector();
        for (int i=0; i<rules.length; i++)
            if (rules[i]!=null)
                if (help.contains(rules[i][0])==false) help.addElement(rules[i][0]);
        String[] answer = new String[help.size()];
        help.copyInto(answer);
        return answer;
    }

    public final String[] terminals() {
        String[][] rules = getRules();
        String[] nonTerminals = nonTerminals();
        Vector help = new Vector();
        boolean isTerminal;
        for (int i=0; i<rules.length; i++)
            if (rules[i]!=null)
                for (int t=0; t<rules[i].length; t++) {
                    isTerminal = true;
                    for (int j=0; j<nonTerminals.length; j++)
                        if (rules[i][t].equals(nonTerminals[j])) {isTerminal = false; break;}
                    if (isTerminal & help.contains(rules[i][t])==false)
                        help.addElement(rules[i][t]);
                }
        String[] answer = new String[help.size()];
        help.copyInto(answer);
        return answer;
    }

    public final String[] symbols() {
        String[] nonTerminals = nonTerminals();
        String[] terminals = terminals();
        String[] symbols = new String[nonTerminals.length+terminals.length];
        System.arraycopy(nonTerminals,0,symbols,0,nonTerminals.length);
        System.arraycopy(terminals,0,symbols,nonTerminals.length,terminals.length);
        return symbols;
    }

    public boolean isNonTerminal(String symbol) {
        String[] nonTerminals = nonTerminals();
        boolean answer = false;
        for (int i=0; i<nonTerminals.length; i++)
            if (symbol.equals(nonTerminals[i])) {answer = true; break;}
        return answer;
    }

    public boolean isTerminal(String symbol) {
        String[] terminals = terminals();
        boolean answer = false;
        for (int i=0; i<terminals.length; i++)
            if (symbol.equals(terminals[i])) {answer = true; break;}
        return answer;
    }

    public final void setInput( SICParserInput pin ) {
        sicPin = pin;
    }

    public final void setInput( String[] pin ) {
        setInput(new SICParserInput(pin));
    }

    public final void setInput( String pinFileName ) throws IOException {
        setInput(new SICParserInput(pinFileName));
    }

    public final void setInput( File pinFile ) throws IOException {
        setInput(new SICParserInput(pinFile));
    }


    public final SICData getInput() {
        return sicPin;
    }


    public final boolean start( File pinFile ) throws IOException {
        return start(new SICParserInput(pinFile));
    }

    public final boolean start( String pinFileName ) throws IOException {
        return start(new SICParserInput(pinFileName));
    }

    public final boolean start( SICParserInput pin ) {
        setInput(pin);
        return start();
    }

    public final boolean start() {
        if (sicPin==null) {
            sicTree = null; sicStack = null;
            return false; }
          else {
            sicStack = new SICStack();
            int index,action,line = 1;

            Enumeration pin = sicPin.elements();
            sicTree = (SICTree)pin.nextElement();

            while (true) {
                action = getAction(line,sicTree.getValue());
                if (action==ERROR | action==ACCEPT) break;

                if (action==SHIFT) {
                    sicStack.push(line,sicTree);
                    sicTree = (SICTree)pin.nextElement();
                } else
                if (action==REDUCE)
                    sicStack.reduce(line,getRule(getIndex(line,sicTree.getValue())));

                line = getIndex(sicStack.peekState(),sicStack.peekTree().getValue());
                sicStack.peekTree().setState(line);
            }

            if (action==ACCEPT) {
                sicTree = sicStack.peekTree();
                sicStack = null;
                return true; }
              else {
                sicStack.push(line,sicTree);
                sicTree = null;
                return false;
            }
        }
    }


    public final SICTree getResult() {
        return sicTree;
    }

    public final String getResultAsString() {
        if (sicTree==null) return null;
          else return sicTree.toString();
    }

    public final void saveResult( String einFileName ) throws IOException {
        saveResult(new File(einFileName));
    }

    public final void saveResult( File einFile ) throws IOException {
        if (sicTree!=null) sicTree.save(einFile);
    }

    public final SICStack getStack() {
        return sicStack;
    }

}




